官方 Demo:https://vueuse.org/core/useEventListener/#useeventlistener
先來說說 useEventListener 這個 API 可以帶來什麼好處~
在寫 Vue 的時候,如果在組件掛載之後有做 DOM event listeners 之類的 side effects,會需要在組件 onUnmounted 的時候移除事件監聽,
如果使用 useEventListener 來註冊事件監聽,就會在組件 onUnmounted 的時候自動移除事件監聽,不用再自己動手寫 removeEventListener,程式碼也會簡潔許多。
target
:傳入要加上 eventListener 的 target,像是 window 或是 HTML element,也可以是 vue3 中的 ref。另外也是可以傳入 null 或是 undefined,不過就不會被 useEventListener 處理,完全不傳 target 的話,預設會是 window。event
:要監聽的事件名稱 。只有一個的話可以傳 string,多個的話就傳入 Array<string>
listener
:傳入在觸發監聽的事件時,要執行的 function。跟 event 一樣,只有一個的話可以傳入 function 就好,多個的話就傳入 Arrayable<Function>
options
:就是 addEventListener 本身可以傳入的 options object。像是 capture, once, passive, signal// src/compositions/useEventListener.js
export function useEventListener(target, event, listener, options) {
let _target
let events
let listeners
let _options = options
if (typeof target === 'string' || Array.isArray(target)) {
_target = defaultWindow
}
_target = target
events = event
listeners = listener
_options = options
if (!_target)
return noop
if (!Array.isArray(events))
events = [events]
if (!Array.isArray(listeners))
listeners = [listeners]
// ...略
};
以上是 useEventListener 對參數處理的部分。
要做到自動在組件註銷前 removeEventListener 的關鍵是 tryOnScopeDispose
。
// src/compositions/useEventListener.js
import { getCurrentScope, onScopeDispose } from 'vue'
export function tryOnScopeDispose(fn) {
if (getCurrentScope()) {
onScopeDispose(fn)
return true
}
return false
}
export function useEventListener(target, event, listener, options) {
// ...略
const stop = () => {
stopWatch()
cleanup()
}
tryOnScopeDispose(stop)
}
這邊用到兩個 Vue 的 API:
getCurrentScope()
:獲取當前的響應式效果作用域(reactive effect scope)。scope 可以是組件 instance 建立時自動生成的,也可以是通過 effectScope() 手動創建的。在 useEventListener 的情境中,通常會在組件的 setup() 函數中調用,所以拿到的會是組件的 scope。
onScopeDispose(fn)
:註冊一個 callback function,該函數將在當前 scope 被銷毀時執行。跟 onUnmounted 類似,但因為它不需要在組件內部調用,所以很適合在 composable function 使用。
在我們知道可以在 composable function 中達成在 effect scope 消除時透過 onScopeDispose 來做些事情,那要傳什麼 function 給 onScopeDispose 讓他執行呢?
在上面程式碼中,傳入的是 stop,在組件 onUnmounted 的時候執行 composable function 內部的 stopWatch 以及 cleanup,cleanup 做的事情就是 removeEventListener。
今天看到了兩個平常比較少用的 Vue API,getCurrentScope()
& onScopeDispose(fn)
,看起來是在寫多組件共用的 composable function 會非常實用,明天會接著把整個 useEventListener 的運作流程一起講完~